今天想延伸昨天的練習:<Provider>
與其他客製化的測試寫法。
昨天我們練習到:要讓測試接收 AppProvider
傳入的值,我們可以在 RTL render()
這個 function 第二個參數設定指定 wrapper
。
import { render, screen } from "@testing-library/react";
import ThemeMode from "./mode";
import AppProvider from "../../providers/providers";
describe("ThemeProvider", () => {
test("Render dark mode correctly!", () => {
render(<ThemeMode />, {
wrapper: AppProvider // 這樣測試就會知道要去注意 AppProvider 提供的內容。
});
const modeEl = screen.getByRole("heading", {
level: 1
});
expect(modeEl).toHaveTextContent("dark mode");
});
});
但這裡會有一個問題,就是 AppProvider
的狀態會傳給所有的components,等於說專案內所有的 components在撰寫測試時,都需要加入 { wrapper: AppProvider }
,是滿麻煩的!
在這種情況,我們可以針對 RTL 提供的 render()
方法,進行客製化調整:
test-utils.tsx
(convention file name for customized render)import { RenderOptions, render } from "@testing-library/react";
import AppProvider from "./providers/providers";
import { ReactElement } from "react";
// 在原 render 方法上,傳入全域 wrapper: AppProvider
const CustomRender = (
ui: ReactElement,
options?: Omit<RenderOptions, 'wrapper'>,
) => render(ui, {
wrapper: AppProvider,
...options, // 其他特定測試要加入 Provider,才不會被預設覆蓋
})
// 匯出 RTL,同時將 CustomRender 視為 render 方法
export * from "@testing-library/react";
export { CustomRender as render };
test-utils.tsx
位置:import { render, screen } from "../../test-utils"; // 修改路徑
import ThemeMode from "./mode";
describe("ThemeProvider", () => {
test("Render dark mode correctly!", () => {
render(<ThemeMode />); // 原個別設定 wrapper 可以拿掉
const modeEl = screen.getByRole("heading", {
level: 1
});
expect(modeEl).toHaveTextContent("dark mode");
});
});